#include "header.hpp"
using namespace std;

//Move semantic
//Format:
//ClassName(ClassName&& other);

class String{
public:
    String() = default;
    String(const char* string){
        printf("%s\n", "Created String");
        m_Size = strlen(string);
        m_Data = new char[strlen(string) + 1]();
        memcpy(m_Data, string, m_Size);
    }

    //Copy Constructor
    String(const String& other){
        printf("%s\n", "Copied");
        m_Size = other.m_Size;
        m_Data = new char[other.m_Size + 1]();
        memcpy(m_Data, other.m_Data, m_Size);
    }

    //※Move Constructor
    //※Format: ClassName(ClassName&& other);
    //※Action: "this" will steal all data of "other" -> shallow copy
    String(String&& other){
        printf("Moved\n");
        //Move all data from "other" to "this"
        m_Size = other.m_Size;
        m_Data = other.m_Data;

        //Recycle the resources of "other"
        other.m_Size = 0;
        other.m_Data = nullptr;
    }

    //※Move assignment operator
    //※Format: ClassName& operator=(ClassName&& other);
    String& operator=(String&& other){
        printf("Moved\n");

        if(this != &other){
            //Release the resource that left-hand-side manages
            delete [] m_Data;

            //Move all data from "other" to "this"
            m_Size = other.m_Size;
            m_Data = other.m_Data;

            //Recycle the resources of "other"
            other.m_Size = 0;
            other.m_Data = nullptr;
        }

        return *this;
    }

    ~String(){
        printf("Destroyed\n");
        delete m_Data;
    }

    void print(){
        printf("%s\n", m_Data);
    }

private:
    char* m_Data;
    uint32_t m_Size;
};



class Entity{
public:
    Entity(const String& name)
        : m_Name(name){}

    Entity(String&& name)
    //Convert "name" to rval by "move", otherwise, this line will invoke copy constructor
        : m_Name(move(name)){
        printf("Constructor of Entity, parameter is rval reference\n");
    }

    void printName(){
        m_Name.print();
    }

private:
    String m_Name;
};



void test2(){
    Entity entity("abc");
    entity.printName();

    cout << "--------------------------------" << endl;

    String string = "hello";
    String dest;

    cout << "string: ";
    string.print();
    cout << "dest: ";
    dest.print();

    dest = move(string);

    cout << "string: ";
    string.print();
    cout << "dest: ";
    dest.print();
}
